using BepuUtilities;
using System.Diagnostics;
using System.Runtime.CompilerServices;
#if MYCODE
using BepuUtilities.Vectors;
#else
using System.Numerics;
#endif

namespace BepuPhysics.Constraints
{
    public struct SpringSettingsWide
    {
        // 摆弄内存布局时要小心。它与行刑顺序一致。
        public Vector<float> AngularFrequency;
        public Vector<float> TwiceDampingRatio;

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void WriteFirst(in SpringSettings source, ref SpringSettingsWide target)
        {
            GatherScatter.GetFirst(ref target.AngularFrequency) = source.AngularFrequency;
            GatherScatter.GetFirst(ref target.TwiceDampingRatio) = source.TwiceDampingRatio;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ReadFirst(in SpringSettingsWide source, out SpringSettings target)
        {
            target.AngularFrequency = source.AngularFrequency[0];
            target.TwiceDampingRatio = source.TwiceDampingRatio[0];
        }

        /// <summary>
        /// 计算一组约束的弹性值。
        /// </summary>
        /// <param name="settings">与约束关联的Spring设置。</param>
        /// <param name="dt">时间点的持续时间。</param>
        /// <param name="position tionErrorToVelocity">应用于错误以获取偏移速度的乘数。</param>
        /// <param name="EfficitiveMassCFMScale">应用于有效质量的比例因子,以获得软化的有效质量。</param>
        /// <param name="softnessImPulseScale">应用于求解过程中累积脉冲的比例因子,以软化目标速度。</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ComputeSpringiness(in SpringSettingsWide settings, float dt,
            out Vector<float> positionErrorToVelocity, out Vector<float> effectiveMassCFMScale, out Vector<float> softnessImpulseScale)
        {
            // 有关这些值背后的详细信息,请查看Inequality1DOF约束注释。
            // 软化有效质量=有效质量*(1+(自然频率^2*dt^2+2*阻尼比*自然频率*dt)^-1)^-1

            // cfm/dt*softenedEffectiveMass值：
            // (自然频率^2*dt^2+2*阻尼比*自然频率*dt)^-1*(1+(自然频率^2*dt^2+2*阻尼比*自然频率*dt)^-1)^-1

            // ERP=(自然频率*dt)*(自然频率*dt+2*阻尼比)^-1
            // "ERP"是每帧减少的误差。请注意,在给定物理有效输入的情况下,它永远不能超过1。
            // 由于它是*每帧*项,请注意,位置误差通过inverseDt进行额外缩放,以获得目标速度
            // 需要在一帧内完成所需的差错减少。
            var angularFrequencyDt = settings.AngularFrequency * new Vector<float>(dt);
            positionErrorToVelocity = settings.AngularFrequency / (angularFrequencyDt + settings.TwiceDampingRatio);
            var extra = Vector<float>.One / (angularFrequencyDt * (angularFrequencyDt + settings.TwiceDampingRatio));
            effectiveMassCFMScale = Vector<float>.One / (Vector<float>.One + extra);
            softnessImpulseScale = extra * effectiveMassCFMScale;
        }
    }

    public struct SpringSettings
    {
        /// <summary>
        /// 每单位时间的目标无阻尼振荡数,按2*PI缩放。
        /// </summary>
        public float AngularFrequency;
        /// <summary>
        /// 弹簧的实际阻尼与临界阻尼之比的两倍。
        /// </summary>
        public float TwiceDampingRatio;

        /// <summary>
        /// 获取或设置每单位时间的目标无阻尼振荡次数。
        /// </summary>
        public float Frequency { get { return AngularFrequency / MathHelper.TwoPi; } set { AngularFrequency = value * MathHelper.TwoPi; } }

        /// <summary>
        /// 获取或设置弹簧的实际阻尼与其临界阻尼之比。0表示无阻尼,1表示严重阻尼,更高的值表示过度阻尼。
        /// </summary>
        public float DampingRatio { get { return TwiceDampingRatio / 2f; } set { TwiceDampingRatio = value * 2; } }

        /// <summary>
        /// 检查弹簧设置实例是否包含有效值。
        /// </summary>
        /// <param name="springSettings">要检查的设置。</param>
        /// <return>如果弹簧设置有效,则为True,否则为False。</return>
        public static bool Validate(in SpringSettings springSettings)
        {
            return ConstraintChecker.IsPositiveNumber(springSettings.AngularFrequency) && ConstraintChecker.IsNonnegativeNumber(springSettings.TwiceDampingRatio);
        }

        /// <summary>
        /// 构造一个新的弹簧设置实例。
        /// </summary>
        /// <param name="Frequency">每单位时间的无阻尼振荡目标数。</param>
        /// 弹簧的实际阻尼与临界阻尼的<param name="DampingRatio">比率。0表示未阻尼,1表示严重阻尼,更高的值则过度阻尼。</param>
        public SpringSettings(float frequency, float dampingRatio)
        {
            AngularFrequency = frequency * MathHelper.TwoPi;
            TwiceDampingRatio = dampingRatio * 2;
            Debug.Assert(Validate(this), "Spring settings must have positive frequency and nonnegative damping ratio.");
        }


    }
}
